#include <application.h>
#include <spdlog/sinks/ansicolor_sink-inl.h>
#include <SDL3/SDL.h>
#include <utl/async.h>
#include <fstream>
#include <utl/time.h>
#include <setting/SettingWindow.h>


namespace
{
	primary::Application* global_instance{};
	int argc{};
	constexpr auto setting_filename{ "setting.cfg" };
}

primary::Application::Application() :logger{ "Tetris",std::make_shared<spdlog::sinks::ansicolor_stderr_sink_mt>() }, q_app{ argc,nullptr }, sdl{}
{
	assert(global_instance == nullptr);
	global_instance = this;
	utl::async_initialize();
	this->main_window = sdl.CreateSDLWindow();
	this->main_renderer = sdl.CreateSDLRenderer(this->main_window.get());
	this->gui = utl::make_unique<GuiSDL>(this->main_window.get(), this->main_renderer.get());
	std::ifstream file{ setting_filename };
	if (file.is_open())
	{
		this->setting.ParseFromIstream(&file);
		u32 setting_mask{};
		if (!this->setting.icon().empty())
		{
			setting_mask |= SCM_ICON;
		}
		if (!this->setting.title().empty())
		{
			setting_mask |= SCM_TITLE;
		}
		this->setting_changed(setting_mask);
	}
}

primary::Application::~Application()
{
	utl::async_shutdown();
	global_instance = nullptr;
}

primary::Application& primary::Application::instance()
{
	assert(global_instance != nullptr);
	return *global_instance;
}

void primary::Application::save_setting(u32 mask)
{
	this->setting_changed(mask);
	for (auto& item : this->setting_changed_callbacks)
	{
		item(this->setting, mask);
	}
	std::ofstream file{ setting_filename };
	assert(file.is_open());
	this->setting.SerializeToOstream(&file);
	
	//TODO 
}

u32 primary::Application::bind_setting(SettingChangedFN fn)
{
	u32 id{ (u32)this->setting_changed_callbacks.size() };
	this->setting_changed_callbacks.push_back(fn);
	return id;
}

void primary::Application::unbind_setting(u32 id)
{
	this->setting_changed_callbacks[id] = this->setting_changed_callbacks.back();
	this->setting_changed_callbacks.pop_back();
}

void primary::Application::unbind_setting(SettingChangedFN fn)
{
	utl::vector_delete_element(this->setting_changed_callbacks, fn);
}

void primary::Application::setting_editor()
{
	SettingWindow sw{ this->setting };
	sw.exec();
}

void primary::Application::run()
{
	bool life{ true };
	auto last_time = utl::time::now();
	SDL_Event e{};
	while (life)
	{
		while (SDL_PollEvent(&e) != 0)
		{
			this->gui->process(&e);
			if (e.type == SDL_EventType::SDL_EVENT_WINDOW_CLOSE_REQUESTED)
			{
				life = false;
			}
		}
		this->gui->render();
		SDL_RenderPresent(this->main_renderer.get());
	}
}

void primary::Application::setting_changed(u32 mask)
{
	if (mask & SCM_ICON)
	{
		utl::image img{ this->setting.icon() };
		auto sf = sdl.CreateSDLSurface(img);
		SDL_SetWindowIcon(this->main_window.get(), sf.get());
	}
	if (mask & SCM_TITLE)
	{
		SDL_SetWindowTitle(this->main_window.get(), this->setting.title().c_str());
	}
}
